package com.kepler.social.domain.support.media;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.kepler.social.common.exception.SystemException;
import com.kepler.social.common.utils.FileUtil;
import com.kepler.social.domain.support.media.converter.MediaConverter;
import com.kepler.social.domain.support.media.vo.M3u8Vo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 领域内的helper只允许被domainService使用
 */
@Component
@Slf4j
public class MediaHelper {

    public static String VIDEO_FOLDER;

    public static String IMAGE_FOLDER;

    @Value("${app.static-files-folder}")
    public void setConfPath(String path) {
        VIDEO_FOLDER = path + "video/";
        IMAGE_FOLDER = path + "image/";
    }

    private Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));

    @Resource
    private RedisTemplate redisTemplate;

    private ObjectMapper objectMapper = new ObjectMapper();

    public String mergeImageSlice(String reqSeq, String originalFileName) throws IOException {
        // 文件名加上UUID，保证文件命不重复
        String fileName = FileUtil.uniFileName(originalFileName);
        // 按照日期生成子目录
        String today = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
        Path targetFolder = this.createPathIAbsent(IMAGE_FOLDER, today);
        Path targetFile = targetFolder.resolve(fileName);
        log.info("slice image merge reqSeq {}  tmp file {}", reqSeq, targetFile);
        this.mergeSliceIntoTargetFile(reqSeq, targetFile);
        return String.join("/", StringUtils.EMPTY, IMAGE_FOLDER, today, fileName);
    }

    /**
     * @param reqSeq           请求序列号
     * @param originalFileName 文件名称
     */
    public M3u8Vo mergeVideoSlice(String reqSeq, String originalFileName) throws IOException {
        // 文件名加上UUID，保证文件命不重复
        String fileName = FileUtil.uniFileName(originalFileName);
        Path tempFile = tempDir.resolve(fileName);
        log.info("slice video merge reqSeq {}  tmp file {}", reqSeq, tempFile);
        this.mergeSliceIntoTargetFile(reqSeq, tempFile);
        return this.storeAsM3U8(fileName.substring(0, fileName.lastIndexOf(".")), tempFile);
    }

    /**
     * 将序列号reqSeq对应的分片数据合并成目标文件targetFile
     *
     * @param reqSeq
     * @param targetFile
     * @throws IOException
     */
    private void mergeSliceIntoTargetFile(String reqSeq, Path targetFile) throws IOException {
        try (RandomAccessFile ra = new RandomAccessFile(targetFile.toString(), "rw")) {
            ra.seek(ra.length());
            while (true) {
                Object value = redisTemplate.opsForList().leftPop(reqSeq);
                if (value == null) {
                    break;
                }
                byte[] buffer = objectMapper.readValue(value.toString(), byte[].class);
                ra.write(buffer, 0, buffer.length);
            }
        } finally {
            redisTemplate.delete(reqSeq);
        }
    }

    /**
     * 将tempFile以title为文件名转化m3u8
     *
     * @param title
     * @param sourceFilePath 文件路径
     * @return
     * @throws IOException
     */
    public M3u8Vo storeAsM3U8(String title, Path sourceFilePath) throws IOException {
        TranscodeConfig transcodeConfig = new TranscodeConfig();
        log.info("转码配置：{}", transcodeConfig);
        try {
            // 按照日期生成子目录
            String today = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
            Path targetFolder = this.createPathIAbsent(VIDEO_FOLDER, today, title);
            // 执行转码操作
            log.info("开始转码");
            try {
                FFmpegUtils.transcodeToM3u8(sourceFilePath.toString(), targetFolder.toString(), transcodeConfig);
            } catch (Exception e) {
                log.error("storeAsM3U8 转码异常：{}", e.getMessage());
                throw new SystemException("生成M3u8异常");
            }
            return MediaConverter.toM3u8Vo(title,
                    String.join("/", StringUtils.EMPTY, VIDEO_FOLDER, today, title, "ts/index.m3u8"),
                    String.join("/", StringUtils.EMPTY, VIDEO_FOLDER, today, title, "poster.jpg"));
        } finally {
            // 始终删除临时文件
            Files.delete(sourceFilePath);
        }
    }

    /**
     * 创建文件夹
     *
     * @param subFolderName 第一个子文件夹
     * @param more
     * @return
     * @throws IOException
     */
    private Path createPathIAbsent(String subFolderName, String... more) throws IOException {
        // 尝试创建视频目录
        Path targetFolder = Files.createDirectories(Paths.get(subFolderName, more));
        log.info("创建文件夹目录：{}", targetFolder);
        Files.createDirectories(targetFolder);
        return targetFolder;
    }

}
